package com.yonggle.springbootdemo.generate;

import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public class ControllerGenerator {

    public static void main(String[] args) {
        InputStream resourceAsStream = ControllerGenerator.class.getClassLoader().getResourceAsStream("controllers.xml");
        Controllers controllers = XmlUtil.toObject(resourceAsStream, Controllers.class);

        Arrays.stream(controllers.getControllers()).forEach(controller -> {

            Set<String> imports = new LinkedHashSet<>();

            imports.add("org.springframework.beans.factory.annotation.Autowired");
            imports.add("org.springframework.web.bind.annotation.*");

            List<String> services = Arrays.stream(controller.getRequests()).map(request -> request.getService())
                    .distinct().collect(Collectors.toList());
            services.stream().forEach(service -> imports.add(controllers.getServiceNamespace() + "." + service));

            StringBuffer sb = new StringBuffer();
            sb.append("@RequestMapping(\"").append(controller.getPath()).append("\")\n");
            sb.append("@RestController\n");
            sb.append("public class ").append(controller.getName()).append(" {\n");

            services.stream().forEach(service -> {
                sb.append("@Autowired\n");
                sb.append("private ").append(service).append(" ").append(service.substring(0,1).toLowerCase()).append(service.substring(1)).append(";\n\n");
            });

            Arrays.stream(controller.getRequests()).forEach(request -> {
                sb.append("@RequestMapping(value = \"").append(request.getPath()).append("\", method = RequestMethod.").append(request.getMethod()).append(")\n");
                try {
                    Class<?> clazz = Class.forName(controllers.getServiceNamespace() + "." + request.getService());
                    Method[] methods = clazz.getMethods();

                    String methodName = request.getInvoke().substring(0, request.getInvoke().indexOf("("));
                    String[] invokeParams = request.getInvoke().substring(request.getInvoke().indexOf("(") + 1, request.getInvoke().lastIndexOf(")")).split(",");

                    Optional<Method> op = Arrays.stream(methods).filter(method -> method.getName().equals(methodName)).findFirst();
                    if (op.isPresent()) {
                        Method method = op.get();

                        imports.add(method.getReturnType().getName());

                        sb.append("public ").append(method.getReturnType().getSimpleName()).append(" ").append(request.getName()).append("(");

                        if (request.getParameters().length > 0) {
                            Arrays.stream(request.getParameters()).forEach(parameter -> {
                                int index = 0;
                                for(; index < invokeParams.length; index++){
                                    if (invokeParams[index].equals(parameter.getName())) {
                                        break;
                                    }
                                }

                                if (index < invokeParams.length) {
                                    imports.add(method.getParameters()[index].getType().getName());
                                    method.getParameters()[index].getType().getSimpleName();
                                    if (Boolean.TRUE.equals(parameter.getRequired())
                                        || (parameter.getDefaultValue() != null)) {
                                        sb.append("@RequestParam(");
                                        if (parameter.getDefaultValue() != null) {
                                            sb.append("defaultValue = \"").append(parameter.getDefaultValue()).append("\"");
                                        }
                                        sb.append(") ");
                                    }
                                    sb.append(method.getParameters()[index].getType().getSimpleName()).append(" ").append(parameter.getName()).append(", ");
                                }
                            });
                            sb.deleteCharAt(sb.length()-1);
                            sb.deleteCharAt(sb.length()-1);
                        }

                        sb.append(") {\n");

                        sb.append("return ").append(request.getService().substring(0,1).toLowerCase()).append(request.getService().substring(1)).append(".").append(request.getInvoke()).append(";\n");

                        sb.append("}\n");

                    }
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            });
            sb.append("}");

            StringBuffer header = new StringBuffer();
            header.append("package ").append(controllers.getControllerNamespace()).append(";\n");
            imports.stream().filter(im -> !im.startsWith("java.lang.")).forEach(im -> {
                header.append("import ").append(im).append(";\n");
            });

            System.out.println(header.toString());
            System.out.println(sb.toString());
        });

    }
}
